import { Injectable } from "@nestjs/common";
import { ValidationDto } from "./dto/validation.dto";
import { createHash } from "node:crypto";
import { HttpService } from "@nestjs/axios";
import { LoggerService } from "@/common/logger/logger.service";
import { firstValueFrom } from "rxjs";
import { handleError } from "@/utils/handle.error";
import { AccountService } from "@/common/account/account.service";
import { RedisService } from "@/common/redis/redis.service";
import { formatTime } from "@/utils/date";
import { BatchSendDto } from "./dto/batch-send.dto";

@Injectable()
export class WechatService {
	constructor(
		private readonly logger: LoggerService,
		private readonly httpService: HttpService,
		private readonly accountService: AccountService,
		private readonly redisService: RedisService,
	) {
		this.logger.setContext(WechatService.name);
	}

	/** 获取openid */
	async wxLogin(js_code: string) {
		try {
			this.logger.log(`${this.wxLogin.name} was called`);
			const { miniAppid: appid, miniSecret: secret } =
				await this.accountService.getExtraInfo();
			const res = await firstValueFrom(
				this.httpService.get<{ openid: string }>(
					"https://api.weixin.qq.com/sns/jscode2session",
					{
						params: {
							appid,
							secret,
							js_code,
							grant_type: "authorization_code",
						},
					},
				),
			);
			return res.data.openid;
		} catch (error) {
			handleError(this.logger, error, {
				common: "获取openid失败",
			});
		}
	}

	/** 获取小程序access_token */
	async getWxAccessToken() {
		try {
			this.logger.log(`${this.getWxAccessToken.name} was called`);
			const access_token = await this.redisService._get("wx_access_token");
			if (access_token) {
				return access_token;
			}

			const { miniAppid: appid, miniSecret: secret } =
				await this.accountService.getExtraInfo();
			const res = await firstValueFrom(
				this.httpService.get<{ access_token: string; expires_in: number }>(
					"https://api.weixin.qq.com/cgi-bin/token",
					{
						params: {
							appid,
							secret,
							grant_type: "client_credential",
						},
					},
				),
			);
			this.redisService._setex(
				"wx_access_token",
				res.data.expires_in,
				res.data.access_token,
			);

			return res.data.access_token;
		} catch (error) {
			handleError(this.logger, error, {
				common: "获取微信access_token失败",
			});
		}
	}

	/** 发送订阅消息 */
	async sendSubscribeMessage(
		openid: string,
		miniprogram_state = "formal", // developer为开发版；trial为体验版；formal为正式版；默认为正式版
		value1 = "每日浇水",
		value2 = formatTime(),
	) {
		try {
			this.logger.log(`${this.sendSubscribeMessage.name} was called`);
			const access_token = await this.getWxAccessToken();
			console.log("打印***access_token", access_token);
			const { miniTemplateId } = await this.accountService.getExtraInfo();
			console.log("打印***miniTemplateId", miniTemplateId);
			const res = await firstValueFrom(
				this.httpService.post(
					`https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=${access_token}`,
					{
						access_token,
						template_id: miniTemplateId,
						page: "pages/dailyCheck/index",
						touser: openid,
						data: {
							thing1: {
								value: value1,
							},
							thing2: {
								value: value2,
							},
						},
						miniprogram_state,
						lang: "zh_CN",
					},
				),
			);
			console.log("打印***res", res.data);
			return res;
		} catch (error) {
			handleError(this.logger, error, {
				common: "发送订阅消息失败",
			});
		}
	}

	/** 批量发送订阅消息 */
	async batchSendMsg(openidList: Array<string>) {
		try {
			this.logger.log(`${this.batchSendMsg.name} was called`);
			openidList.forEach((openid) => {
				this.sendSubscribeMessage(openid);
			});
			return "批量发送成功";
		} catch (error) {
			handleError(this.logger, error, {
				common: "批量发送订阅消息失败",
			});
		}
	}

	/** 验证签名 */
	async checkSignature({
		signature,
		echostr,
		timestamp,
		nonce,
	}: ValidationDto) {
		// 将token、timestamp、nonce三个参数进行字典序排序
		const stringArray = ["snowball", timestamp, nonce];
		const resultArray = stringArray.sort();
		// 将三个参数字符串拼接成一个字符串进行sha1加密
		const resultString = resultArray.join("");
		const hashResult = createHash("sha1").update(resultString).digest("hex");
		const isWechatHost = hashResult === signature;
		console.log("打印***hashResult", hashResult);
		console.log("打印***signature", signature);
		return isWechatHost ? echostr : "";
	}
}
